//==================================================================================================
/**
  EVE - Expressive Vector Engine
  Copyright : EVE Project Contributors
  SPDX-License-Identifier: BSL-1.0
**/
//==================================================================================================
#include "test.hpp"

#include <eve/module/core.hpp>

#include <cmath>

//==================================================================================================
// Types tests
//==================================================================================================
TTS_CASE_TPL("Check return types of eve::minus", eve::test::simd::signed_types_wf16)
<typename T>(tts::type<T>)
{
  using v_t = eve::element_type_t<T>;

  TTS_EXPR_IS(eve::minus(T()), T);
  TTS_EXPR_IS(eve::minus[eve::logical<T>()](T()), T);
  TTS_EXPR_IS(eve::minus[eve::logical<v_t>()](T()), T);
  TTS_EXPR_IS(eve::minus[bool()](T()), T);

  TTS_EXPR_IS(eve::minus[eve::saturated](T()), T);
  TTS_EXPR_IS(eve::minus[eve::logical<T>()][eve::saturated](T()), T);
  TTS_EXPR_IS(eve::minus[eve::logical<v_t>()][eve::saturated](T()), T);
  TTS_EXPR_IS(eve::minus[bool()][eve::saturated](T()), T);

  TTS_EXPR_IS(eve::minus(v_t()), v_t);
  TTS_EXPR_IS(eve::minus[eve::logical<v_t>()](v_t()), v_t);
  TTS_EXPR_IS(eve::minus[bool()](v_t()), v_t);

  TTS_EXPR_IS(eve::minus[eve::saturated](v_t()), v_t);
  TTS_EXPR_IS(eve::minus[eve::logical<v_t>()][eve::saturated](v_t()), v_t);
  TTS_EXPR_IS(eve::minus[bool()][eve::saturated](v_t()), v_t);

};

//==================================================================================================
// Tests for eve::minus
//==================================================================================================
TTS_CASE_WITH("Check behavior of eve::minus(eve::wide)",
              eve::test::simd::signed_types_wf16,
              tts::generate(tts::randoms(-10, +10), tts::logicals(0, 3)))
<typename T, typename M>(T const& a0, M const& mask)
{
  using v_t = eve::element_type_t<T>;

  TTS_EQUAL(eve::minus(a0), tts::map([](auto e) -> v_t { return -e; }, a0));
  TTS_EQUAL(eve::minus[mask](a0), eve::if_else(mask, eve::minus(a0), a0));
  TTS_EQUAL(eve::minus[eve::if_(mask).else_(99)](a0), eve::if_else(mask, eve::minus(a0), T{99}));
  TTS_EQUAL(eve::minus[eve::ignore_all](a0), a0);
  TTS_EQUAL(eve::minus[eve::ignore_all.else_(42)](a0), T{42});
};

//==================================================================================================
// Tests for eve::minus[eve::saturated]
//==================================================================================================
TTS_CASE_WITH("Check behavior of eve::minus[eve::saturated](eve::wide)",
              eve::test::simd::signed_types_wf16,
              tts::generate(tts::randoms(eve::valmin, eve::valmax), tts::logicals(0, 3)))
<typename T, typename M>(T const& a0, M const& mask)
{

  TTS_EQUAL(eve::minus[eve::saturated](a0),
            tts::map([](auto e)
                { return e == eve::valmin(eve::as(e)) ? eve::valmax(eve::as(e)) : eve::minus(e); },
                a0));
  TTS_EQUAL(eve::minus[mask][eve::saturated](a0),
            eve::if_else(mask, eve::minus[eve::saturated](a0), a0));
};

//==================================================================================================
// Test for corner-cases values
//==================================================================================================
TTS_CASE_TPL("Check corner-cases behavior of eve::minus variants on wide",
             eve::test::simd::signed_types_wf16)
<typename T>(tts::type<T> tgt)
{
  auto cases = tts::limits(tgt);

  if constexpr( eve::floating_value<T> )
  {
    TTS_IEEE_EQUAL(eve::minus(cases.nan), cases.nan);
    TTS_IEEE_EQUAL(eve::minus(cases.minf), cases.inf);
    TTS_EQUAL(eve::minus(cases.mzero), T(0));
    TTS_EQUAL(eve::minus(cases.valmin), cases.valmax);
    TTS_EQUAL(eve::minus(cases.valmax), cases.valmin);
  }
  else
  {
    TTS_EQUAL(eve::minus[eve::saturated](cases.valmin), cases.valmax);
    TTS_EQUAL(eve::minus(cases.valmax), cases.valmin + 1);
    TTS_EQUAL(eve::minus(T(0)), T(0));
  }
};

//==================================================================================================
//==  minus modular tests
//==================================================================================================
TTS_CASE_WITH("Check behavior of minus mod on wide",
              eve::test::simd::ieee_reals_wf16,
              tts::generate(tts::randoms(0, 96))
             )
  <typename T>(T const& ra0)
{
  using eve::minus;
  using eve::mod;
  auto a0 = eve::floor(ra0);
  using e_t =  eve::element_type_t<T>;
  e_t p = 97;
  TTS_ULP_EQUAL(minus[mod = p](a0), eve::if_else(eve::is_eqz(a0), a0, p-a0), 0.5);
};
